package org.feng.interceptor;

import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.Builder;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.feng.annotions.SensitiveData;
import org.feng.sensitive.AbstractSensitive;
import org.feng.util.SensitiveUtil;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * 处理密文拦截器
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2023年08月24日 23时07分
 */
@Slf4j
@Builder
@Accessors(chain = true)
public class MybatisPlusSensitiveInterceptor implements InnerInterceptor {

    /**
     * 全局的加/解密处理
     */
    private AbstractSensitive sensitive;

    @Override
    public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) {
        // 执行加密操作
        executeSensitive(parameter);
    }

    private void executeSensitive(Object parameter) {
        Class<?> entityClass = parameter.getClass();
        // 当前实体类有标注了SensitiveEntity注解
        if (SensitiveUtil.isSensitiveEntity(parameter)) {
            Field[] fields = entityClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(SensitiveData.class)) {
                    SensitiveData sensitiveData = field.getAnnotation(SensitiveData.class);
                    String sensitiveType = sensitiveData.sensitiveType();
                    // 字段注解传的sensitiveType有值
                    if (StringUtils.hasLength(sensitiveType)) {
                        // 获取缓存中的实例
                        AbstractSensitive sensitiveByType = AbstractSensitive.getSensitiveByType(sensitiveType);
                        if (Objects.isNull(sensitiveByType)) {
                            throw new RuntimeException("加解密类型设置错误,类型不存在");
                        }
                        // 重置变量的值
                        SensitiveUtil.encryptFieldValue(field, parameter, sensitiveByType);
                        continue;
                    } else if (Objects.nonNull(sensitive)) {
                        // 重置变量的值
                        SensitiveUtil.encryptFieldValue(field, parameter, sensitive);
                        continue;
                    }
                    throw new RuntimeException("未指定加、解密类型");
                }
            }
        }
    }
}
